﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using PSE.Framework.IO;
using Sinacor.Infra.UI.Controls.SmartClient.Validation;

namespace Sinacor.Infra.UI.Controls.SmartClient
{
    [DefaultProperty("Value")]
    public partial class SinacorFilePicker : Control, IValidatableObject
    {
        private const string RequiredValidationRuleName = "RequiredValidator";
        private const string FilePickerValidationRuleName = "FilePickerValidationRule";

        SinacorTextBox txtPath;
        SinacorButton btSearch_Text;
        SinacorButton btSearch_Icon;
        System.Windows.Forms.OpenFileDialog fileDialog;
        public event FileSucessfullySelectedHandler FileSucessfullySelected;
        public delegate void FileSucessfullySelectedHandler(object sender, FileSucessfullySelectedEventArgs e);

        public static readonly DependencyProperty WidthPathProperty = DependencyProperty.Register("WidthPath", typeof(double), typeof(SinacorFilePicker), new FrameworkPropertyMetadata((double)50));
        public double WidthPath
        {
            get { return (double)GetValue(WidthPathProperty); }
            set { SetValue(WidthPathProperty, value); }
        }

        public static readonly DependencyProperty WidthButtonProperty = DependencyProperty.Register("WidthButton", typeof(double), typeof(SinacorFilePicker), new FrameworkPropertyMetadata((double)70));
        public double WidthButton
        {
            get { return (double)GetValue(WidthButtonProperty); }
            set { SetValue(WidthButtonProperty, value); }
        }

        public static readonly DependencyProperty ShowIconOnButtonProperty = DependencyProperty.Register("ShowIconOnButton", typeof(bool), typeof(SinacorFilePicker), new FrameworkPropertyMetadata(false));
        public bool ShowIconOnButton
        {
            get { return (bool)GetValue(ShowIconOnButtonProperty); }
            set { SetValue(ShowIconOnButtonProperty, value); }
        }

        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(SinacorFilePicker), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
        public string Value
        {
            get { return (string)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        public static readonly DependencyProperty IsRequiredProperty = DependencyProperty.Register("IsRequired", typeof(bool), typeof(SinacorFilePicker), new FrameworkPropertyMetadata(false, OnIsRequiredPropertyChanged));
        public bool IsRequired
        {
            get { return (bool)GetValue(IsRequiredProperty); }
            set { SetValue(IsRequiredProperty, value); }
        }

        public static readonly DependencyProperty RequiredErrorMessageProperty = DependencyProperty.Register("RequiredErrorMessage", typeof(string), typeof(SinacorFilePicker), new FrameworkPropertyMetadata("Infra.Controls.Message.CampoObrigatorio", OnRequiredErrorMessagePropertyChanged));
        public string RequiredErrorMessage
        {
            get { return (string)GetValue(RequiredErrorMessageProperty); }
            set { SetValue(RequiredErrorMessageProperty, value); }
        }

        public static readonly DependencyProperty InvalidFileErrorMessageProperty = DependencyProperty.Register("InvalidFileErrorMessage", typeof(string), typeof(SinacorFilePicker), new FrameworkPropertyMetadata("Infra.Controls.Message.ArquivoNaoEncontrado", OnInvalidFileErrorMessagePropertyChanged));
        public string InvalidFileErrorMessage
        {
            get { return (string)GetValue(InvalidFileErrorMessageProperty); }
            set { SetValue(InvalidFileErrorMessageProperty, value); }
        }

        public static readonly DependencyProperty ValidateIfPathExistsProperty = DependencyProperty.Register("ValidateIfPathExists", typeof(bool), typeof(SinacorFilePicker), new FrameworkPropertyMetadata(true, OnValidateIfPathExistsPropertyChanged));
        public bool ValidateIfPathExists
        {
            get { return (bool)GetValue(ValidateIfPathExistsProperty); }
            set { SetValue(ValidateIfPathExistsProperty, value); }
        }

        public bool AddExtension
        {
            get { return fileDialog.AddExtension; }
            set { fileDialog.AddExtension = value; }
        }

        public bool AutoUpgradeEnabled
        {
            get { return fileDialog.AutoUpgradeEnabled; }
            set { fileDialog.AutoUpgradeEnabled = value; }
        }

        public bool CheckFileExists
        {
            get { return fileDialog.CheckFileExists; }
            set { fileDialog.CheckFileExists = value; }
        }

        public bool CheckPathExists
        {
            get { return fileDialog.CheckPathExists; }
            set { fileDialog.CheckPathExists = value; }
        }

        public bool RestoreDirectory
        {
            get { return fileDialog.RestoreDirectory; }
            set { fileDialog.RestoreDirectory = value; }
        }

        public bool ShowHelp
        {
            get { return fileDialog.ShowHelp; }
            set { fileDialog.ShowHelp = value; }
        }

        public bool ShowReadOnly
        {
            get { return fileDialog.ShowReadOnly; }
            set { fileDialog.ShowReadOnly = value; }
        }

        public bool ValidateNames
        {
            get { return fileDialog.ValidateNames; }
            set { fileDialog.ValidateNames = value; }
        }

        public string InitialDirectory
        {
            get { return fileDialog.InitialDirectory; }
            set { fileDialog.InitialDirectory = value; }
        }

        public string DefaultExt
        {
            get { return fileDialog.DefaultExt; }
            set { fileDialog.DefaultExt = value; }
        }

        public string Filter
        {
            get { return fileDialog.Filter; }
            set { fileDialog.Filter = value; }
        }

        public string Title
        {
            get { return fileDialog.Title; }
            set { fileDialog.Title = TryFindResource(value) != null ? (string)TryFindResource(value) : null; }
        }

        public FileAccessRigths FilePermissions
        {
            get
            {
                if (txtPath != null)
                {
                    string path = txtPath.Text;
                    if (!String.IsNullOrEmpty(path) && System.IO.File.Exists(path))
                        return new FileAccessRigths(path);
                    else
                        return null;
                }
                return null;
            }
        }

        //-------------------------------------------------------------------------------------------------------------

        public SinacorFilePicker()
        {
            ValidationManager.InitializeValidation(this);
            this.PrepareDialogs();
        }

        protected virtual void CreateValidations()
        {
            if (!this.ValidationRules.Contains(RequiredValidationRuleName))
            {
                RequiredValidationRule reqValidation = new RequiredValidationRule(this, SinacorFilePicker.ValueProperty);
                reqValidation.Name = RequiredValidationRuleName;

                this.ValidationRules.Add(reqValidation);

                reqValidation.ErrorContent = this.RequiredErrorMessage;
                reqValidation.IsEnabled = this.IsRequired;
            }
            if (!this.ValidationRules.Contains(FilePickerValidationRuleName))
            {
                FilePickerValidationRule filePickerValidation = new FilePickerValidationRule(this, SinacorFilePicker.ValueProperty);
                filePickerValidation.Name = FilePickerValidationRuleName;

                this.ValidationRules.Add(filePickerValidation);

                filePickerValidation.ErrorContent = this.InvalidFileErrorMessage;
                filePickerValidation.IsEnabled = this.ValidateIfPathExists;
            }
        }

        protected virtual void UpdateValitadions()
        {
            if (this.ValidationRules.Contains(RequiredValidationRuleName))
            {
                RequiredValidationRule reqValidation = this.ValidationRules[RequiredValidationRuleName] as RequiredValidationRule;
                if (reqValidation != null)
                {
                    reqValidation.ErrorContent = RequiredErrorMessage;
                    reqValidation.IsEnabled = this.IsRequired;
                }
            }
            if (this.ValidationRules.Contains(FilePickerValidationRuleName))
            {
                FilePickerValidationRule filePickerValidation = this.ValidationRules[FilePickerValidationRuleName] as FilePickerValidationRule;
                if (filePickerValidation != null)
                {
                    filePickerValidation.ErrorContent = this.InvalidFileErrorMessage;
                    filePickerValidation.IsEnabled = this.ValidateIfPathExists;
                }
            }
        }

        protected virtual void CreateValidationTriggers()
        {
            EventValidationTrigger trigger = new EventValidationTrigger(ValidationTriggerScope.Self, LostFocusEvent);
            trigger.ContinueRoutingOnError = true;
            if (!this.ValidationTriggers.Contains(trigger))
            {
                this.ValidationTriggers.Add(trigger);
            }
        }

        static void OnIsRequiredPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            SinacorFilePicker instance = d as SinacorFilePicker;
            if (instance != null)
                instance.UpdateValitadions();
        }

        static void OnRequiredErrorMessagePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            SinacorFilePicker instance = d as SinacorFilePicker;
            if (instance != null)
                instance.UpdateValitadions();
        }

        static void OnInvalidFileErrorMessagePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            SinacorFilePicker instance = d as SinacorFilePicker;
            if (instance != null)
                instance.UpdateValitadions();
        }

        static void OnValidateIfPathExistsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            SinacorFilePicker instance = d as SinacorFilePicker;
            if (instance != null)
                instance.UpdateValitadions();
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            txtPath = this.GetTemplateChild("PART_txtPath") as SinacorTextBox;
            btSearch_Text = this.GetTemplateChild("PART_btSearch_Text") as SinacorButton;
            btSearch_Icon = this.GetTemplateChild("PART_btSearch_Icon") as SinacorButton;

            txtPath.MaxLength = 256;
            btSearch_Text.Click += new RoutedEventHandler(Search_Click);
            btSearch_Icon.Click += new RoutedEventHandler(Search_Click);

            btSearch_Text.Visibility = !ShowIconOnButton ? Visibility.Visible : Visibility.Collapsed;
            btSearch_Icon.Visibility = ShowIconOnButton ? Visibility.Visible : Visibility.Collapsed;

            Binding bd = new Binding("Value");
            bd.Mode = BindingMode.TwoWay;
            bd.UpdateSourceTrigger = UpdateSourceTrigger.LostFocus;
            bd.RelativeSource = RelativeSource.TemplatedParent;
            this.txtPath.SetBinding(SinacorTextBox.TextProperty, bd);

            CreateValidations();
            CreateValidationTriggers();
        }

        void Search_Click(object sender, RoutedEventArgs e)
        {
            if (!String.IsNullOrEmpty(txtPath.Text))
                fileDialog.InitialDirectory = txtPath.Text;

            switch (fileDialog.ShowDialog())
            {
                case System.Windows.Forms.DialogResult.OK:
                    if (fileDialog.FileNames.Length > 0)
                    {
                        Value = fileDialog.FileName;
                        txtPath.Text = fileDialog.FileName;
                    }
                    break;
                default:
                    break;
            }
        }

        void PrepareDialogs()
        {
            fileDialog = new System.Windows.Forms.OpenFileDialog();
            fileDialog.DefaultExt = DefaultExt;
            fileDialog.Filter = Filter;
            fileDialog.Title = Title;
            fileDialog.AddExtension = AddExtension;
            fileDialog.AutoUpgradeEnabled = AutoUpgradeEnabled;
            fileDialog.CheckFileExists = CheckFileExists;
            fileDialog.CheckPathExists = CheckPathExists;
            fileDialog.InitialDirectory = InitialDirectory;
            fileDialog.RestoreDirectory = RestoreDirectory;
            fileDialog.ShowHelp = ShowHelp;
            fileDialog.ShowReadOnly = ShowReadOnly;
            fileDialog.ValidateNames = ValidateNames;
            fileDialog.Multiselect = false;
            fileDialog.FileOk += new System.ComponentModel.CancelEventHandler(fileDialog_FileOk);
        }

        void fileDialog_FileOk(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (FileSucessfullySelected != null)
                FileSucessfullySelected(this, new FileSucessfullySelectedEventArgs(fileDialog.FileName, fileDialog.FileNames));
        }

        //-------------------------------------------------------------------------------------------------------------

        public static readonly DependencyProperty CanValidateProperty = ValidationManager.CanValidateProperty.AddOwner(typeof(SinacorFilePicker));
        public static readonly DependencyProperty ValidationGroupProperty = ValidationManager.ValidationGroupProperty.AddOwner(typeof(SinacorFilePicker));
        public static readonly DependencyProperty ClearServiceErrorsProperty = ValidationManager.ClearServiceErrorsProperty.AddOwner(typeof(SinacorFilePicker));
        public static readonly DependencyProperty CausesValidationProperty = ValidationManager.CausesValidationProperty.AddOwner(typeof(SinacorFilePicker));
        public static readonly DependencyProperty ValidationTriggersProperty = ValidationManager.ValidationTriggersProperty.AddOwner(typeof(SinacorFilePicker));
        public static readonly DependencyProperty ValidationRulesProperty = ValidationManager.ValidationRulesProperty.AddOwner(typeof(SinacorFilePicker));
        public static readonly DependencyProperty HasErrorProperty = ValidationManager.HasErrorProperty.AddOwner(typeof(SinacorFilePicker));
        public static readonly DependencyProperty ErrorsProperty = ValidationManager.ErrorsProperty.AddOwner(typeof(SinacorFilePicker));
        public static readonly DependencyProperty ErrorTemplateProperty = ValidationManager.ErrorTemplateProperty.AddOwner(typeof(SinacorFilePicker));

        public bool CanValidate
        {
            get { return (bool)GetValue(CanValidateProperty); }
        }
        public string ValidationGroup
        {
            get { return (string)GetValue(ValidationGroupProperty); }
            set { SetValue(ValidationGroupProperty, value); }
        }
        public bool ClearServiceErrors
        {
            get { return (bool)GetValue(ClearServiceErrorsProperty); }
            set { SetValue(ClearServiceErrorsProperty, value); }
        }
        public bool CausesValidation
        {
            get { return (bool)GetValue(CausesValidationProperty); }
            set { SetValue(CausesValidationProperty, value); }
        }
        public bool HasError
        {
            get { return (bool)GetValue(HasErrorProperty); }
        }
        public bool Validate()
        {
            return ValidationManager.Validate(this);
        }
        public bool Validate(DependencyProperty property)
        {
            return ValidationManager.Validate(this, property);
        }
        public bool ValidateParentContainer()
        {
            return ValidationManager.ValidateParentContainer(this);
        }
        public ValidationTriggerCollection ValidationTriggers
        {
            get { return (ValidationTriggerCollection)GetValue(ValidationTriggersProperty); }
        }
        public ValidationRuleCollection ValidationRules
        {
            get { return (ValidationRuleCollection)GetValue(ValidationRulesProperty); }
        }
        public ReadOnlyObservableCollection<ValidationError> Errors
        {
            get { return (ReadOnlyObservableCollection<ValidationError>)GetValue(ErrorsProperty); }
        }
        public ControlTemplate ErrorTemplate
        {
            get { return (ControlTemplate)GetValue(ErrorTemplateProperty); }
            set { SetValue(ErrorTemplateProperty, value); }
        }
    }

    public class FileSucessfullySelectedEventArgs : EventArgs
    {
        string _selectedFilePath;
        string[] _selectedFilesPath;

        public string SelectedFilePath
        {
            get { return _selectedFilePath; }
            set { _selectedFilePath = value; }
        }
        public string[] SelectedFilesPath
        {
            get { return _selectedFilesPath; }
            set { _selectedFilesPath = value; }
        }

        public FileSucessfullySelectedEventArgs(string selectedFilePath, string[] selectedFilesPath)
        {
            _selectedFilePath = selectedFilePath;
            _selectedFilesPath = selectedFilesPath;
        }
    }
}